#include "osal/osal.h"
#include "utils/debug/log.h"
#include "utils/reboot_trace/reboot_trace.h"
#include "hal/hal_wdt.h"
#include "ln_nvds.h"
#include "ln_utils.h"

#include "wifi_manager.h"
#include "wifi.h"

#include "usr_app.h"
#include "usr_ble_app.h"
#include "ln_ty_ate.h"
#include "ln_ty_sdk_version.h"
#include "uni_log.h"
#include "tuya_iot_config.h"

#define USR_WORK_THREAD_STACK_SIZE   4*256 //Byte

#if (TY_RTC == 1)
extern uint8_t platform_rtc_cal(void);
#endif

static void dump_task_stack_info(void)
{
    static UBaseType_t   s_arraySize = 0;
    static TaskStatus_t  *s_task_status_array_p = NULL;
    uint32_t      FreeRTOSRunTimeTicks = 0;
    UBaseType_t   cnt = 0;

    static uint8_t is_runned = 0;

    if (is_runned == 0) {
        s_arraySize = uxTaskGetNumberOfTasks();
        s_task_status_array_p = pvPortMalloc(s_arraySize * sizeof(TaskStatus_t));
        LOG(LOG_LVL_ERROR, "alloc size:%d\r\n", s_arraySize * sizeof(TaskStatus_t));

        if (s_task_status_array_p != NULL) {
            is_runned = 1;
        } else {
            return;
        }
    }

    if (is_runned == 1) {
        cnt = uxTaskGetSystemState(
                        (TaskStatus_t *)s_task_status_array_p,
                        (UBaseType_t)s_arraySize,
                        (uint32_t *)&FreeRTOSRunTimeTicks);

        LOG(LOG_LVL_INFO,"\r\n=============================================\r\n");
        LOG(LOG_LVL_INFO,
                "TaskName    Priority    TaskNumber    MinStk    tick\r\n");
        for(int x = 0; x < cnt; x++) {
            LOG(LOG_LVL_INFO,
                "%8.8s    %02d          %02d            %06d    %ld\r\n",
                s_task_status_array_p[x].pcTaskName,
                (int)s_task_status_array_p[x].uxCurrentPriority,
                (int)s_task_status_array_p[x].xTaskNumber,
                (int)s_task_status_array_p[x].usStackHighWaterMark * sizeof(StackType_t),
                (int)((float)s_task_status_array_p[x].ulRunTimeCounter/FreeRTOSRunTimeTicks*100));
        }
        LOG(LOG_LVL_INFO,"=============================================\r\n");
    }
}

static void usr_work_task_entry(void *arg)
{
    uint8_t cnt = 0;
    LN_UNUSED(arg);
    uint8_t delay_cnt = 0;
    // Delay output of necessary logs
    OS_MsDelay(2000);
#if (TY_RTC == 1)
    tuya_rtc_init();
#endif
    {
        /**
         * Note: chip-en connected to GND means power-down!!!
        */
        LOG(LOG_LVL_INFO, "reboot type(0:power-on;1:soft-rst;2:wdt-rst): %d\r\n",
                ln_chip_get_reboot_cause());

        /**
         * s_hw_reboot_cnt:
         *     Statistics of restart times without power-down.
         * Note: chip-en connected to GND means power-down!!!
        */
        LOG(LOG_LVL_INFO, "reboot count: %d\r\n", usr_reboot_cnt_get());

        LOG(LOG_LVL_INFO, "[ln_ty_sdk_ver: %s or 0x%08x] [build time:%s]\r\n",
            LN_TY_SDK_VERSION_STRING, LN_TY_SDK_VERSION, LN_TY_SDK_BUILD_DATE_TIME);

        LOG(LOG_LVL_INFO, "[Git info: %s]\r\n", LN_TY_SDK_GIT_INFO);

        LOG(LOG_LVL_INFO, "[BLIB Ver: %s or 0x%08x] [build time:%s]\r\n",
                ble_lib_version_string_get(),
                ble_lib_version_number_get(),
                ble_lib_build_time_get());
    }

    while(1)
    {
        if ((delay_cnt % 10) == 0)
        {
            extern void *heap0_len;
            extern void ln_main_stack_attr_get(uint8_t **start_addr, size_t *size);

            #define HEAP_TOTAL_LEN    (&heap0_len)
            uint8_t *stack_start_addr = NULL;
            size_t   stack_size = 0;
            ln_main_stack_attr_get(&stack_start_addr, &stack_size);

            LOG(LOG_LVL_INFO, 
                "Total:%ld; Free:%ld; main stack:%ld;\r\n", 
                (size_t)HEAP_TOTAL_LEN, OS_GetFreeHeapSize(), stack_size);
            // dump_task_stack_info();
        }
#if (TY_RTC == 1)
        {
             platform_rtc_cal();
        }
#endif
        OS_MsDelay(1000);
        delay_cnt++;
    }

    OS_ThreadDelete(NULL);
}

#define LN_SELF_ATE_TEST_MODE (0)
#define LN_SELF_NORMAL_ADD_ATE_UART (0)

#if (LN_SELF_ATE_TEST_MODE)
bool self_test_ty_ate_mode_check(void)
{
    return true;
}
#endif

static void ty_main_task_entry(void *arg)
{
    LN_UNUSED(arg);

#if (LN_SELF_ATE_TEST_MODE)
    LOG(LOG_LVL_INFO, "Enter ate mode!\r\n");
    ln_nvds_set_ate_result(NV9_ATE_RESULT_OK);
    ln_ty_ate_main(self_test_ty_ate_mode_check);
#elif (LN_SELF_NORMAL_ADD_ATE_UART)
    LOG(LOG_LVL_INFO, "Enter Normal mode, but have ate uart cmd!\r\n");
    user_main();
    extern int ln_ty_ate_uart_test_use_start(void);
    ln_ty_ate_uart_test_use_start();
#else
    if (0 != ln_ty_ate_main(ln_ty_ate_mode_check)) {
        LOG(LOG_LVL_INFO, "Failed to enter ate mode! Start tuya user main.\r\n");
        user_main();
    }

    extern int ln_ty_ate_uart_test_use_start(void);
    ln_ty_ate_uart_test_use_start();
#endif /* LN_SELF_ATE_TEST_MODE */
    SetLogManageAttr(TY_LOG_LEVEL_TRACE);

    OS_ThreadDelete(NULL);
}

void creat_usr_app_task(void)
{
    /**
     * create init task
    */
    {
        OS_Thread_t work_task = {0};
        if(OS_OK != OS_ThreadCreate(&work_task, "worker",
            usr_work_task_entry, NULL,
            OS_PRIORITY_BELOW_NORMAL, USR_WORK_THREAD_STACK_SIZE)) {
            LOG(LOG_LVL_ERROR, "Failed to create cal task!\r\n");
        }
    }

    /**
     * create tuya main task
    */
    {
#define TY_MAIN_TASK_STACK_SIZE (4 * 1024)
        OS_Thread_t ty_main_thr = {0};
        if(OS_OK != OS_ThreadCreate(&ty_main_thr, "ty_main", ty_main_task_entry,
            NULL, OS_PRIORITY_NORMAL, TY_MAIN_TASK_STACK_SIZE)) {
            LOG(LOG_LVL_ERROR, "Failed to create TY task!\r\n");
        }
    }
}

void ln_wdt_start(void)
{
    wdt_init_t_def wdt_init;
    memset(&wdt_init, 0, sizeof(wdt_init));
    wdt_init.wdt_rmod = WDT_RMOD_1;
    wdt_init.wdt_rpl = WDT_RPL_32_PCLK;
    wdt_init.top = WDT_TOP_VALUE_10;
    hal_wdt_init(WDT_BASE, &wdt_init);

    NVIC_EnableIRQ(WDT_IRQn);

    hal_wdt_en(WDT_BASE, HAL_ENABLE);
    hal_wdt_cnt_restart(WDT_BASE);
}

void WDT_IRQHandler()
{
}
